package com.example.demo.rabbitMQ.config;

import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.transaction.RabbitTransactionManager;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * <p>Description: 统一配置 RabbitTemplate </p>
 *
 * <p>如果消息没有到exchange,则confirm回调,ack=false
 * <p>
 * 如果消息到达exchange,则confirm回调,ack=true
 * <p>
 * exchange到queue成功,则不回调return
 * <p>
 * exchange到queue失败,则回调return(需设置mandatory=true,否则不回回调,消息就丢了) </p>
 *
 * @author Eric Lee
 * @version v1.0.0
 * @since 2021/8/3 17:02
 **/
@ConditionalOnProperty(prefix = "rabbitmq", name = "enable", havingValue = "true")
@Configuration
public class RabbitMqConfig {


    //  声明开发服务器rabbitTemplate
    @Bean("rabbitTemplate")
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        CachingConnectionFactory factory = (CachingConnectionFactory) connectionFactory;
        factory.addConnectionListener(new ConnectionListener() {
            @Override
            public void onCreate(Connection connection) {
                System.err.println("端口：" + connection.getLocalPort());
            }
        });
        RabbitTemplate rabbitTemplate = new RabbitTemplate(factory);

        rabbitTemplate.setMandatory(true);
        // 启用事务模式,不能开确认回调,两者是排他的
        rabbitTemplate.setConfirmCallback(new RabbitMqCallback());
//        rabbitTemplate.setChannelTransacted(true);
        // 触发setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
        rabbitTemplate.setReturnsCallback(new RabbitMqCallback());
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    /**
     * 配置启用rabbitmq事务
     *
     * @param connectionFactory
     * @return
     */
    @Bean("rabbitTransactionManager")
    public RabbitTransactionManager rabbitTransactionManager(CachingConnectionFactory connectionFactory) {
        return new RabbitTransactionManager(connectionFactory);
    }

    @Bean
    public MessageConverter jackson2JsonMessageConverter(){
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        return jackson2JsonMessageConverter;
    }


// ---------------------------------------------

    // 注意这里使用了primary注解
    //  声明连接工厂连接开发服务器
//    @Primary
    @Bean(name = "devConnectionFactory")
    public ConnectionFactory devConnectionFactory(@Value("${spring.rabbitmq.host}") String host,
                                                  @Value("${spring.rabbitmq.port}") int port,
                                                  @Value("${spring.rabbitmq.username}") String username,
                                                  @Value("${spring.rabbitmq.password}") String password) {
        // 使用@Value直接读取配置文件中的信息
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setPublisherConfirms(true);
        connectionFactory.setPublisherReturns(true);
        return connectionFactory;
    }

    /**
     * 声明dev containerFactory
     *
     * @param rabbitListenerContainerFactoryConfigurer
     * @param connectionFactory
     * @return
     */
    @Bean(name = "devContainerFactory")
    public SimpleRabbitListenerContainerFactory devSimpleRabbitListenerContainerFactory(
            SimpleRabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactoryConfigurer,
            @Qualifier("devConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
        rabbitListenerContainerFactoryConfigurer.configure(containerFactory, connectionFactory);
        return containerFactory;
    }

    //  声明开发服务器rabbitTemplate
    @Bean(name = "devRabbitTemplate")
    public RabbitTemplate devRabbitTemplate(
            @Qualifier("devConnectionFactory") ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

}
